#include "KMutex.h"

KRWLock::KRWLock() : 
    m_nRead(0),
    m_nWaitingRead(0),
    m_nWaitingWrite(0),
    m_state(KRWLock::Idle)
{
}

void KRWLock::lockRead()
{
    bool signaled = false;
    for (;;) {
        {
            KMutex lock(m_entry);
            if (signaled) {
                --m_nWaitingRead;
            }
            switch (m_state) {
            case KRWLock::Idle:
                m_state = KRWLock::Reading;
                ++m_nRead;
                return;
            case KRWLock::Reading:
                if (m_nWaitingWrite > 0) {
            case KRWLock::Writing:
                    ++m_nWaitingRead;
                    m_event.reset();
                } else {
                    ++m_nRead;
                    return;
                } break;
            }
        }
        m_event.wait();
        signaled = true;
    }
}

void KRWLock::lockWrite()
{
    bool signaled = false;
    for (;;) {
        {
            KMutex lock(m_entry);
            if (signaled) {
                --m_nWaitingWrite;
            }
            switch (m_state) {
            case KRWLock::Idle:
                m_state = KRWLock::Writing;
                return;
            case KRWLock::Reading:
            case KRWLock::Writing:
                ++m_nWaitingWrite;
                m_event.reset();
                break;
            }
        }
        m_event.wait();
        signaled = true;
    }
}

void KRWLock::unlock()
{
    KMutex lock(m_entry);
    if (m_nRead > 0 && --m_nRead > 0) {
        return;
    }
    m_state = KRWLock::Idle;
    if (m_nWaitingRead > 0 || m_nWaitingWrite > 0) {
        m_event.set();
    }
}